using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using oms.Modules.System.Models;

namespace oms.Shared.Data;

/// <summary>
/// 应用数据库上下文，用于数据库交互
/// </summary>
/// <param name="options">数据库上下文选项</param>
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
    // 仅注册实体集合（必须）
    public DbSet<SysUserEntity> SysUsers => Set<SysUserEntity>();
    public DbSet<SysRoleEntity> SysRoles => Set<SysRoleEntity>();
    public DbSet<SysUserRoleEntity> SysUserRoles => Set<SysUserRoleEntity>();


    /// <summary>
    /// 配置 DbContextOptionsBuilder，用于设置数据库连接和提供器
    /// </summary>
    /// <param name="optionsBuilder">数据库上下文选项构建器</param>
    public void ConfigureOptionsBuilder(DbContextOptionsBuilder<AppDbContext> optionsBuilder)
    {
        optionsBuilder.UseMySql(
            Database.GetDbConnection().ConnectionString, // 获取当前连接字符串
            ServerVersion.AutoDetect(Database.GetDbConnection().ConnectionString)
        );
    }


    /// <summary>
    /// 配置模型创建，用于定义实体和数据库表之间的映射关系
    /// </summary>
    /// <param name="modelBuilder">模型构建器</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var converterCache = new Dictionary<Type, ValueConverter>();

        // 遍历所有实体，依次处理表名、列名（含枚举转换）、索引名
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            // 1. 处理表名（移除Entity后缀 + 转下划线）
            ProcessTableName(entityType);

            // 2. 处理列名（转下划线）+ 枚举转换器
            ProcessColumns(entityType, converterCache);

        }

        // 加载其他配置
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);

        // 应用实体配置（从程序集加载所有实现 IEntityTypeConfiguration<T> 的类）
        ApplyEntityConfigurations(modelBuilder);
    }

    /// <summary>
    /// 处理列名（驼峰转下划线）+ 同步处理枚举转换器
    /// </summary>
    private static void ProcessColumns(IMutableEntityType entityType, Dictionary<Type, ValueConverter> converterCache)
    {
        foreach (var property in entityType.GetProperties())
        {
            // 处理列名（驼峰转下划线）
            ProcessColumnName(property);

            // 处理枚举值转换器
            RegisterEnumValueConverters(property, converterCache);
        }
    }

    /// <summary>
    /// 处理列名（驼峰转下划线）
    /// </summary>
    private static void ProcessColumnName(IMutableProperty property)
    {
        if (property.PropertyInfo != null)
        {
            var notMappedAttribute = property.PropertyInfo.GetCustomAttribute<NotMappedAttribute>();
            if (notMappedAttribute != null)
            {
                return;
            }

            var columnAttribute = property.PropertyInfo.GetCustomAttribute<ColumnAttribute>();
            if (columnAttribute != null && !string.IsNullOrEmpty(columnAttribute.Name))
            {
                return;
            }
        }
        
        // 处理列名：驼峰转下划线
        var columnName = ConvertToSnakeCase(property.Name);
        property.SetColumnName(columnName);
    }


    /// <summary>
    /// 处理表名：移除Entity后缀 + 帕斯卡转下划线
    /// </summary>
    private static void ProcessTableName(IMutableEntityType entityType)
    {
        // 步骤1：检查是否有 [Table] 特性，有则直接返回（EF Core 会自动应用）
        var tableAttribute = entityType.ClrType.GetCustomAttribute<TableAttribute>();
        if (tableAttribute != null && !string.IsNullOrEmpty(tableAttribute.Name))
        {
            return; // 无需手动设置，EF Core 已处理
        }

        // 步骤2：无 [Table] 特性，基于实体类名生成表名
        var entityClassName = entityType.ClrType.Name;
        var nameWithoutSuffix = RemoveEntitySuffix(entityClassName);
        var snakeCaseName = ConvertToSnakeCase(nameWithoutSuffix);

        entityType.SetTableName(snakeCaseName); // 仅无特性时手动设置
    }


    /// <summary>
    /// 注册值转换器，用于将C#类型转换为数据库存储值
    /// </summary>
    /// <param name="property">模型构建器</param>
    /// <param name="converterCache">转换器缓存字典</param>
    private static void RegisterEnumValueConverters(IMutableProperty property,
        Dictionary<Type, ValueConverter> converterCache)
    {
        // 处理枚举转换器：检查是否标记了[EnumConverterAttribute]
        var propertyInfo = property.PropertyInfo;
        if (propertyInfo?.GetCustomAttribute<EnumConverterAttribute>() == null) return;
        // 获取枚举类型（处理可空枚举）
        var enumType = property.ClrType.IsEnum
            ? property.ClrType
            : (property.ClrType.IsGenericType && property.ClrType.GetGenericTypeDefinition() == typeof(Nullable<>)
                ? property.ClrType.GenericTypeArguments[0]
                : null);

        if (enumType?.IsEnum != true) return;
        // 构建转换器类型并缓存
        var converterType = typeof(GenericEnumConverter<>).MakeGenericType(enumType);
        if (!converterCache.TryGetValue(converterType, out var converter))
        {
            converter = Activator.CreateInstance(converterType) as ValueConverter
                        ?? throw new InvalidOperationException($"无法创建转换器：{converterType.FullName}");
            converterCache[converterType] = converter;
        }

        // 应用转换器和字段类型
        property.SetValueConverter(converter);
        property.SetColumnType("varchar(50)");
    }


    /// <summary>
    /// 驼峰/帕斯卡转下划线的核心方法
    /// </summary>
    private static string ConvertToSnakeCase(string name)
    {
        if (string.IsNullOrEmpty(name)) return name;

        return Regex.Replace(
                name,
                "(?<!^)(?=[A-Z])", // 在大写字母前添加下划线（非开头位置）
                "_"
            )
            .ToLower();
    }

    // 工具方法：移除实体类名的"Entity"后缀
    private static string RemoveEntitySuffix(string name)
    {
        return name.EndsWith("Entity", StringComparison.Ordinal)
            ? name[..^6]
            : name;
    }


    /// <summary>
    /// 应用实体配置（从程序集加载所有实现 IEntityTypeConfiguration 的类）
    /// </summary>
    /// <param name="modelBuilder"></param>
    private static void ApplyEntityConfigurations(ModelBuilder modelBuilder)
    {
        // 1. 获取配置类所在的程序集（以 UserEntityConfiguration 为锚点）
        var assembly = typeof(IEnabledConfiguration).Assembly;

        // 2. 扫描程序集中所有实现了 IEntityTypeConfiguration<T> 的类
        var allConfigTypes = assembly.GetTypes()
            .Where(t => t is { IsClass: true, IsAbstract: false }) // 排除抽象类
            .Where(t => t.GetInterfaces().Any(i =>
                i.IsGenericType &&
                i.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
            )); // 只保留实现了 IEntityTypeConfiguration<T> 的类

        // 3. 筛选：只加载命名空间包含 "Sys.User" 或 "Sys.Role" 的配置类
        var filteredConfigTypes = allConfigTypes
            .Where(t => t.Namespace != null &&
                        (t.Namespace.Contains("Sys.User") || t.Namespace.Contains("Sys.Role")));

        // 4. 手动加载筛选后的配置类
        foreach (var configType in filteredConfigTypes)
        {
            // 创建配置类实例（假设配置类有默认构造函数）
            var configInstance = Activator.CreateInstance(configType);

            // 获取配置类实现的泛型接口（IEntityTypeConfiguration<TEntity>）
            var entityType = configType.GetInterfaces()
                .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
                .GetGenericArguments()[0]; // 得到 TEntity 类型

            // 调用 modelBuilder.ApplyConfiguration<TEntity>(configInstance)
            var applyMethod = typeof(ModelBuilder)
                .GetMethod("ApplyConfiguration")
                ?.MakeGenericMethod(entityType);
            applyMethod?.Invoke(modelBuilder, [configInstance]);
        }
    }
}